package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 功能：自定义切面类，实现公共字段的填充
 * 作者：4204001140
 * 日期：2024/4/13 21:34
 */

@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    // 这里可以定义切点，指定哪些方法需要被拦截
    // 例如：@Pointcut("execution(* com.sky.service.*.*(..))")
    // 拦截com.sky.service包下的所有类的所有方法 并且，必须有AutoFill注解的方法
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){}


    // 拦截后实现通知
    @Before("autoFillPointCut()")       // 表示进入切入点就进行通知，因为你需要对方法进行前置处理，给实体类加入公共字段，然后才执行sql语句
    public void autoFill(JoinPoint joinPoint){      // joinPoint表示连接点，即被拦截的方法，通过他可以获取被拦截的方法的信息

        log.info("开始执行自动填充公共字段...");

        // 获取被拦截方法的操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
        OperationType operationType = annotation.value();

        // 获取被拦截方法的参数
        Object[] args = joinPoint.getArgs();
        if (args.length == 0 || args == null){  // 避免参数为空
            return;
        }

        Object entity = args[0];  // 设第一个参数是实体类对象

        // 准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        // 根据不同的操作类型，给不同的参数赋值
        if (operationType == OperationType.INSERT){
            // 赋值：创建时间、更新时间、创建人、更新人
            try {
                // 获取参数的赋值方法
                Method setCreateTime = entity.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                // 通过反射将参数赋值到参数实体中
                setCreateTime.invoke(entity, now);
                setCreateUser.invoke(entity, currentId);
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);
            }catch (Exception e){
                e.printStackTrace();
            }
        }else if (operationType == OperationType.UPDATE){
            // 赋值：更新时间、更新人
            // 获取参数的赋值方法
            try {
                Method setUpdateTime = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                // 通过反射将参数赋值到参数实体中
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);
            }catch (Exception e){
                e.printStackTrace();
            }
        }



    }

}
